package com.wechat.page.chat.popup;

import org.springframework.beans.factory.annotation.Autowired;

import com.swak.entity.YesNo;
import com.swak.fx.support.FXMLView;
import com.swak.fx.support.Popup;
import com.swak.fx.support.ui.UI;
import com.swak.fx.support.ui.UI.Locations;
import com.swak.fx.support.ui.UIAction;
import com.swak.fx.support.ui.UICell;
import com.swak.fx.support.ui.UIIcon;
import com.swak.fx.support.ui.UILabel;
import com.swak.fx.support.ui.UIScrollPane;
import com.swak.fx.support.ui.UISearchBar;
import com.swak.ui.Event;
import com.swak.utils.Objects;
import com.wechat.Cons;
import com.wechat.dto.ChatDTO;
import com.wechat.dto.ChatRoomDTO;
import com.wechat.dto.ContactDTO;
import com.wechat.enums.ContactType;
import com.wechat.page.MainPage;
import com.wechat.page.api.ChatApi;
import com.wechat.page.api.ChatRoomApi;
import com.wechat.page.api.ContactApi;
import com.wechat.page.chat.misc.FlagForm;
import com.wechat.page.chat.misc.MoreBtn;
import com.wechat.page.chat.misc.ProfileForm;
import com.wechat.page.contact.card.ContactThumbsComp;

import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
import javafx.geometry.Rectangle2D;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Window;

/**
 * ProfilePopup.
 * 
 * @author DELL
 */
@FXMLView(title = "属性", value = "ProfilePopup.fxml", css = "ProfilePopup.css")
public class ProfilePopup extends Popup {

	private UIScrollPane root;
	private GridPane content;

	private UISearchBar searchInput;
	private ContactThumbsComp contacts;
	private MoreBtn moreBtn;
	private ProfileForm profileForm;
	private UICell chatsAction;
	private FlagForm flagForm;

	private UIAction clearAction;
	private UIAction exitAction;

	@Autowired
	private ChatApi chatApi;
	@Autowired
	private ChatRoomApi roomApi;
	@Autowired
	private ContactApi contactApi;

	public ProfilePopup() {
		this.root = (UIScrollPane) super.root;
		this.content = new GridPane();
		this.searchInput = new UISearchBar();
		this.contacts = this.NewComp(ContactThumbsComp.class);
		this.moreBtn = new MoreBtn();
		this.profileForm = new ProfileForm();
		this.chatsAction = new UICell();
		this.flagForm = new FlagForm();
		this.clearAction = new UIAction();
		this.exitAction = new UIAction();
	}

	@Override
	public void initializeParts() {
		super.initializeParts();
		this.popup.locationProperty().set(Locations.RIGHT_CENTER);
		this.root.setContent(this.content);
		this.root.setFitToWidth(true);
		this.root.setHbarPolicy(ScrollBarPolicy.NEVER);
		this.root.setVbarPolicy(ScrollBarPolicy.NEVER);

		this.content.getChildren().add(this.searchInput);
		GridPane.setConstraints(this.searchInput, 0, 0);
		GridPane.setHgrow(this.searchInput, Priority.ALWAYS);
		GridPane.setVgrow(this.searchInput, Priority.NEVER);
		GridPane.setMargin(this.searchInput, new Insets(0, 0, 24, 0));

		this.content.getChildren().add(this.contacts.getRoot());
		GridPane.setConstraints(this.contacts.getRoot(), 0, 1);
		GridPane.setHgrow(this.contacts.getRoot(), Priority.ALWAYS);
		GridPane.setVgrow(this.contacts.getRoot(), Priority.NEVER);
		GridPane.setMargin(this.contacts.getRoot(), new Insets(0, 0, 12, 0));

		this.content.getChildren().add(this.moreBtn);
		GridPane.setConstraints(this.moreBtn, 0, 2);
		GridPane.setHgrow(this.moreBtn, Priority.ALWAYS);
		GridPane.setVgrow(this.moreBtn, Priority.NEVER);

		this.content.getChildren().add(this.profileForm);
		GridPane.setConstraints(this.profileForm, 0, 3);
		GridPane.setHgrow(this.profileForm, Priority.ALWAYS);
		GridPane.setVgrow(this.profileForm, Priority.NEVER);

		this.chatsAction.getStyleClass().add("chats-action");
		this.chatsAction.valueNodeProperty().set(new UILabel("聊天记录"));
		this.chatsAction.opsNodeProperty().set(new UIIcon(UI.Icons.RIGHT));
		this.content.getChildren().add(this.chatsAction);
		GridPane.setConstraints(this.chatsAction, 0, 4);
		GridPane.setHgrow(this.chatsAction, Priority.ALWAYS);
		GridPane.setVgrow(this.chatsAction, Priority.NEVER);

		this.content.getChildren().add(this.flagForm);
		GridPane.setConstraints(this.flagForm, 0, 5);
		GridPane.setHgrow(this.flagForm, Priority.ALWAYS);
		GridPane.setVgrow(this.flagForm, Priority.NEVER);

		this.clearAction.getStyleClass().add("clear-action");
		this.clearAction.textNodeProperty().set(new UILabel("清空聊天记录"));
		this.content.getChildren().add(this.clearAction);
		GridPane.setConstraints(this.clearAction, 0, 6);
		GridPane.setHgrow(this.clearAction, Priority.ALWAYS);
		GridPane.setVgrow(this.clearAction, Priority.NEVER);

		this.exitAction.getStyleClass().add("exit-action");
		this.exitAction.textNodeProperty().set(new UILabel("退出群聊"));
		this.content.getChildren().add(this.exitAction);
		GridPane.setConstraints(this.exitAction, 0, 7);
		GridPane.setHgrow(this.exitAction, Priority.ALWAYS);
		GridPane.setVgrow(this.exitAction, Priority.NEVER);
	}

	@Override
	public void setupEventHandlers() {
		super.setupEventHandlers();
	}

	@Override
	public void setupBindings() {
		super.setupBindings();
		this.contacts.chatProperty().bind(this.chatProperty);
		this.flagForm.chatProperty().bind(this.chatProperty);
		this.searchInput.visibleProperty().bind(this.isChatroomProperty);
		this.searchInput.managedProperty().bind(this.isChatroomProperty);
		this.profileForm.managedProperty().bind(this.isChatroomProperty);
		this.exitAction.visibleProperty().bind(this.isChatroomProperty);
		this.exitAction.managedProperty().bind(this.isChatroomProperty);
		this.profileForm.visibleProperty().bind(this.isChatroomProperty);
		this.profileForm.contactProperty().bind(this.contactProperty);
		this.profileForm.chatroomProperty().bind(this.chatroomProperty);
	}

	@Override
	public void setupValueChangedListeners() {
		super.setupValueChangedListeners();
		this.setupValueChangedListeners_ProfileForm();
		this.setupValueChangedListeners_flagForm();
		this.chatProperty.addListener((ob, o, n) -> this.onLoadContact(n));
		this.contactProperty.addListener((ob, o, n) -> this.onLoadContact(n));
	}

	// ================================================================================
	// 加载数据
	// ================================================================================
	private void onLoadContact(ChatDTO chat) {
		if (chat != null) {
			this.$run(() -> contactApi.get(chat.getId()).thenAccept(contact -> this.contactProperty.set(contact)));
		}
	}

	private void onLoadContact(ContactDTO contact) {
		if (contact == null) {
			return;
		}

		// 查询具体的联系人
		if (contact.getType() != null && contact.getType() == ContactType.Chat_Room.getType()) {
			this.onLoadChatRoom(contact);
		}
	}

	private void onLoadChatRoom(ContactDTO contact) {
		this.$run(() -> roomApi.get(contact.getId()).thenAccept(room -> this.chatroomProperty.set(room)));
	}

	// ================================================================================
	// 设置显示名称等
	// ================================================================================
	void setupValueChangedListeners_ProfileForm() {
		this.profileForm.nameEditProperty().addListener((ob, o, n) -> {
			this.$run(() -> this.saveNameProfile(n));
		});
		this.profileForm.aliasEditProperty().addListener((ob, o, n) -> {
			this.$run(() -> this.saveAliasProfile(n));
		});
		this.profileForm.displayNameEditProperty().addListener((ob, o, n) -> {
			this.$run(() -> this.saveDisplayNameProfile(n));
		});
	}

	void saveNameProfile(String text) {
		ContactDTO contact = this.contactProperty.get();
		if (contact != null && Objects.equals(contact.getNickName(), text)) {
			return;
		}
		this.contactApi.saveNickName(ContactDTO.of().setId(contact.getId()).setNickName(text))//
				.thenApply(res -> contact.setNickName(res.getNickName()))//
				.thenAccept(res -> this.postCmd(ChatDTO.of().setId(contact.getId())));//
	}

	void saveAliasProfile(String text) {
		ContactDTO contact = this.contactProperty.get();
		if (contact != null && Objects.equals(contact.getAlias(), text)) {
			return;
		}
		this.contactApi.saveAlias(ContactDTO.of().setId(contact.getId()).setAlias(text))//
				.thenApply(res -> contact.setAlias(res.getAlias()))//
				.thenAccept(res -> this.postCmd(ChatDTO.of().setId(contact.getId())));//
	}

	void saveDisplayNameProfile(String text) {
		ChatRoomDTO room = this.chatroomProperty.get();
		if (room != null && Objects.equals(room.getDisplayName(), text)) {
			return;
		}
		this.roomApi.saveDisplayName(ChatRoomDTO.of().setId(room.getId()).setDisplayName(text))//
				.thenApply(res -> room.setDisplayName(res.getDisplayName()));//
	}

	// ================================================================================
	// 设置属性
	// ================================================================================

	void setupValueChangedListeners_flagForm() {
		this.flagForm.displayNickNameChangeProperty().addListener((ob, o, n) -> {
			this.$run(() -> this.saveDisplayNickNameFlag(n));
		});
		this.flagForm.alertChangeProperty().addListener((ob, o, n) -> {
			this.$run(() -> this.saveAlertFlag(n));
		});
		this.flagForm.topChangeProperty().addListener((ob, o, n) -> {
			this.$run(() -> this.saveTopFlag(n));
		});
		this.flagForm.friendChangeProperty().addListener((ob, o, n) -> {
			this.$run(() -> this.saveFriendFlag(n));
		});
	}

	private void saveDisplayNickNameFlag(boolean checked) {
		byte flag = checked ? YesNo.Yes.getType() : YesNo.No.getType();
		ChatDTO chat = this.chatProperty.get();
		if (chat != null && Objects.equals(chat.getIsDnn(), flag)) {
			return;
		}
		this.chatApi.updateFlag(ChatDTO.of().setId(chat.getId()).setIsDnn(flag))
				.thenApply(res -> chat.setIsDnn(res.getIsDnn())).thenAccept(res -> this.postCmd(res));
	}

	private void saveAlertFlag(boolean checked) {
		byte flag = checked ? YesNo.No.getType() : YesNo.Yes.getType();
		ChatDTO chat = this.chatProperty.get();
		if (chat != null && Objects.equals(chat.getIsAlert(), flag)) {
			return;
		}
		this.chatApi.updateFlag(ChatDTO.of().setId(chat.getId()).setIsAlert(flag))
				.thenApply(res -> chat.setIsAlert(res.getIsAlert())).thenAccept(res -> this.postCmd(res));
	}

	private void saveTopFlag(boolean checked) {
		byte flag = checked ? YesNo.Yes.getType() : YesNo.No.getType();
		ChatDTO chat = this.chatProperty.get();
		if (chat != null && Objects.equals(chat.getIsTop(), flag)) {
			return;
		}
		this.chatApi.updateFlag(ChatDTO.of().setId(chat.getId()).setIsTop(flag))
				.thenApply(res -> chat.setIsTop(res.getIsTop())).thenAccept(res -> this.postCmd(res));
	}

	private void saveFriendFlag(boolean checked) {
		byte flag = checked ? YesNo.Yes.getType() : YesNo.No.getType();
		ChatDTO chat = this.chatProperty.get();
		if (chat != null && Objects.equals(chat.getIsFriend(), checked)) {
			return;
		}
		this.chatApi.updateFlag(ChatDTO.of().setId(chat.getId()).setIsFriend(flag))
				.thenApply(res -> chat.setIsFriend(res.getIsFriend())).thenAccept(res -> this.postCmd(res));
	}

	private void postCmd(ChatDTO chat) {
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("[聊天属性] - 发送事件 ：{}", Cons.Event_Chat_Reload);
		}
		this.$post(Event.of().setKey(Cons.Event_Chat_Reload).setMessage(chat));
	}

	// ================================================================================
	// Properties
	// ================================================================================
	@Override
	public void show(Window owner) {
		double height = owner.getHeight() - MainPage.ADJUST_SIZE * 2;
		this.root.setPrefHeight(height);
		super.show(owner, -MainPage.ADJUST_SIZE);
	}

	@Override
	protected Rectangle2D rectifyRectangle2D(Window window, double anchorX, double anchorY, double width,
			double heigth) {
		double popupWidth = this.root.prefWidth(-1);
		Rectangle2D bounds = this.getScreen(window).getVisualBounds();
		this.root.getStyleClass().remove("left");
		if (popupWidth + anchorX + MainPage.ADJUST_SIZE >= bounds.getMaxX()) {
			this.root.getStyleClass().add("left");
			return new Rectangle2D(anchorX - popupWidth, anchorY + 65, width, heigth - 65);
		}
		// 样式的原因需要减除
		return new Rectangle2D(anchorX - 5, anchorY - 5, width, heigth);
	}

	// ================================================================================
	// Properties
	// ================================================================================
	private final ObjectProperty<ChatRoomDTO> chatroomProperty = new SimpleObjectProperty<>();
	private final ObjectProperty<ContactDTO> contactProperty = new SimpleObjectProperty<>();
	private final ObjectProperty<ChatDTO> chatProperty = new SimpleObjectProperty<>();

	public ProfilePopup setChat(ChatDTO chat) {
		this.chatProperty.set(chat);
		return this;
	}

	private BooleanBinding isChatroomProperty = Bindings.createBooleanBinding(() -> {
		ChatDTO chat = this.chatProperty.get();
		return chat != null && chat.getType() == ContactType.Chat_Room.getType();
	}, this.chatProperty);

	// ================================================================================
	// Instance
	// ================================================================================
	private static ProfilePopup instance;

	public static ProfilePopup newPopup() {
		if (instance == null) {
			synchronized (ProfilePopup.class) {
				if (instance == null) {
					instance = ProfilePopup.New(ProfilePopup.class);
				}
			}
		}
		return instance;
	}
}
